#pragma once
#include <unistd.h>
#include <vector>
#include <string>
#include <semaphore.h>
#include "Task.hpp"
#define defaultnum 5
template<class T>
class RingQueue
{
private:

    void Lock(pthread_mutex_t& lock)
    {
        pthread_mutex_lock(&lock);
    }

    void UnLock(pthread_mutex_t& lock)
    {
        pthread_mutex_unlock(&lock);
    }

    void P(sem_t& sem)
    {
        sem_wait(&sem);
    }

    void V(sem_t& sem)
    {
        sem_post(&sem);
    }
public:
    RingQueue(int cap = defaultnum) :cap_(cap), tasks_(cap)
    {
        sem_init(&p_space_sem_, 0, cap_);
        sem_init(&c_data_sem_, 0, 0);
        pthread_mutex_init(&p_lock_, nullptr);
        pthread_mutex_init(&c_lock_, nullptr);

    }

    void Push(const T& t)
    {
        P(p_space_sem_); //再加锁之前申请信号量，1.因为申请信号量是原子的 2.可以让多个线程同时拥有信号量
        Lock(p_lock_); 
        tasks_[p_step_] = t;

        //维护循环队列特性
        p_step_++;
        p_step_ %= cap_;

        UnLock(p_lock_);
        V(c_data_sem_);
    }

    T Pop()
    {
        P(c_data_sem_);
        Lock(c_lock_);
        T t = tasks_[c_step_];
        //维护循环队列特性
        c_step_++;
        c_step_ %= cap_;

        UnLock(c_lock_);
        V(p_space_sem_);

        return t;
    }

    ~RingQueue()
    {
        sem_destroy(&p_space_sem_);
        sem_destroy(&c_data_sem_);
        pthread_mutex_destroy(&p_lock_);
        pthread_mutex_destroy(&c_lock_);
    }
private:
    
    std::vector<T> tasks_; //数组模拟环形队列
    int cap_;
    
    int p_step_; //生产者步调
    int c_step_; //消费者步调

    sem_t p_space_sem_; //生产者关注的空间信号量
    sem_t c_data_sem_;  //消费者关注的数据信号量

    pthread_mutex_t p_lock_; //生产者锁
    pthread_mutex_t c_lock_; //消费者锁
};